package com.baikeyang.app.shiro;

import com.baikeyang.common.constant.CommonConstants;
import com.baikeyang.common.model.User;
import com.baikeyang.service.role.IRoleService;
import com.baikeyang.service.user.IUserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Set;

/**
 * 认证数据源:自定义Realm验证、授权
 * Created by lenovo on 2018/7/12.
 */
@Service
@Transactional
public class MyRealm extends AuthorizingRealm {

    @Autowired
    private IUserService userService;
    @Autowired
    private IRoleService roleService;

    /**
     * 授权方法, 为当前登录的Subject授予角色和权限
     * @param principals 用户身份信息
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        User token = (User)SecurityUtils.getSubject().getPrincipal();

        Long userId = token.getId();
        SimpleAuthorizationInfo info =  new SimpleAuthorizationInfo();
        //根据用户ID查询角色（role），放入到Authorization里。
        Set<String> roles = userService.getRoleByUserId(userId);
        info.setRoles(roles);
        //根据用户ID查询权限（permission），放入到Authorization里。
        Set<String> permissions = roleService.getResourceByRoleIds(roles);
        info.setStringPermissions(permissions);
        return info;
    }

    /**
     * 身份认证
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
        String username = token.getPrincipal().toString();
        String password = new String((char[])token.getCredentials());

        User user = userService.getUserByLoginName(username);
        if(null != user){
            SimpleAuthenticationInfo authcInfo = new SimpleAuthenticationInfo(user, user.getPassword(), getName());
            // 将用户数据存储在Session中
            Session session = SecurityUtils.getSubject().getSession();
            session.setAttribute(CommonConstants.SESSION_USER_KEY, user);
            return authcInfo;

        }else{
            System.out.println("用户【" + username +"】不存在！");
            return null;
        }
    }

    @Override
    public void clearCachedAuthorizationInfo(PrincipalCollection principals) {
        super.clearCachedAuthorizationInfo(principals);
    }

    @Override
    public void clearCachedAuthenticationInfo(PrincipalCollection principals) {
        super.clearCachedAuthenticationInfo(principals);
    }

    @Override
    public void clearCache(PrincipalCollection principals) {
        super.clearCache(principals);
    }

    public void clearAllCachedAuthorizationInfo() {
        Cache<Object, AuthorizationInfo> cache = getAuthorizationCache();
        if(null != cache) {
            cache.clear();
        }
    }

    public void clearAllCachedAuthenticationInfo() {
        Cache<Object, AuthenticationInfo> cache = getAuthenticationCache();
        if(null != cache) {
            cache.clear();
        }
    }

    public void clearAllCache() {
        clearAllCachedAuthenticationInfo();
        clearAllCachedAuthorizationInfo();
    }

}
